using System;
using System.Linq;
using JetBrains.Annotations;
using Kaleida.ServiceMonitor.Model.Email;
using log4net;

namespace Kaleida.ServiceMonitor.Model
{
    public class ScheduledSummaryEmailer : IServiceMonExtension
    {
        private static readonly ILog log = LogManager.GetLogger(typeof (ScheduledSummaryEmailer));
        private readonly Monitor monitor;
        private readonly NotificationMessageBuilder builder = new NotificationMessageBuilder();
        private readonly OperationStatisticsMap statsSinceLastSummary = new OperationStatisticsMap();

        [CanBeNull]
        private ScriptEmailSender emailSender;

        public ScheduledSummaryEmailer(Monitor monitor)
        {
            this.monitor = monitor;
        }

        public void ScriptCompilationComplete(ScriptCompilationCompleteEventArgs args)
        {
            if(args.ScriptCompilation.Succeeded)
            {
				statsSinceLastSummary.Initialise(monitor.CompiledModule.Operations);
            }
        }

        public void OnStartedMonitoring()
        {
			var recipients = monitor.CompiledModule.EmailSummarySchedule.Recipients;
            if (recipients.Any())
            {
				var scriptName = monitor.CompiledModule.Name;
                {
                    emailSender = new ScriptEmailSender(scriptName, recipients);
                    emailSender.Configure(monitor.Application.Configuration);
                    statsSinceLastSummary.Start();
                }
            }
        }

        public void OnStoppedMonitoring()
        {
        }

        public void OnOperationSuccessful(OperationSuccessfulEventArgs args)
        {
            lock (this)
            {
                statsSinceLastSummary.IncrementSuccessCount(args.Operation, args.Result.RequestDuration);
            }
        }

        public void OnOperationFailed(OperationFailedEventArgs args)
        {
            lock (this)
            {
                statsSinceLastSummary.IncrementFailureCount(args.Operation);
            }
        }

        public void OnErrorsAcknowledged()
        {
        }

        public void OnScheduledTimeTick(MinuteTimerTickEventArgs eventArgs)
        {
            if (monitor.State.IsMonitoring)
            {
                var schedule = monitor.CompiledModule.EmailSummarySchedule;

                if(schedule.Recipients.Any())
                {
                    lock (this)
                    {
                        var firstMatch = schedule.Times.FirstOrDefault(i => eventArgs.Time == i);

                        if (firstMatch != null)
                        {
                            var message = builder.BuildSummary(monitor, statsSinceLastSummary);

                            if (message != null && emailSender != null)
                            {
                                TrySendEmailAndLog(message);

                                statsSinceLastSummary.ResetAll();
                                statsSinceLastSummary.Start();
                            }
                        }
                    }
                }
            }
        }

        private void TrySendEmailAndLog(NotificationMessage message)
        {
            if (emailSender == null) throw new InvalidOperationException("ScriptEmailSender has not been set");
            log.DebugFormat("Sending email from monitor {0} for module {1} ({2})", monitor.Id, monitor.CompiledModule.Name, monitor.CompiledModule.Id);
            emailSender.TrySendEmail(message);
            log.DebugFormat("Sent email from monitor {0} for module {1} ({2})", monitor.Id, monitor.CompiledModule.Name, monitor.CompiledModule.Id);
        }
    }
}